package com.trade.data.job;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.trade.data.dto.PredictInfoDto;
import com.trade.data.dto.common.CountPredictInfoDto;
import com.trade.data.manager.PredictManager;
import com.trade.data.model.ModelEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

/**
 * 统计预测信息
 */
@Component
@Slf4j
public class CountPredictJob {
    @Autowired
    PredictManager predictManager;

    /**
     * 读取某个币种 某个周期，某个策略的信息，生成对应的excel和统计信息
     */


    @Scheduled(cron = "25 0,5,10,15,20,25,30,35,40,45,50,55 * * * ?")
    public void executeProduceExcelTask5m() {
        readCoinPeriodStrategyExcel("1000satsusdt","5m",ModelEnum.random_forest);
        readCoinPeriodStrategyExcel("1000satsusdt","5m",ModelEnum.random_forest_v1);
    }
    @Scheduled(cron = "25 0,15,30,45 * * * ?")
    public void executeProduceExcelTask15m() {
        readCoinPeriodStrategyExcel("1000satsusdt","15m",ModelEnum.random_forest);
        readCoinPeriodStrategyExcel("1000satsusdt","15m",ModelEnum.random_forest_v1);
    }
    @Scheduled(cron = "25 0,30 * * * ?")
    public void executeProduceExcelTask30m() {
        readCoinPeriodStrategyExcel("1000satsusdt","30m",ModelEnum.random_forest);
        readCoinPeriodStrategyExcel("1000satsusdt","30m",ModelEnum.random_forest_v1);
    }

    @Scheduled(cron = "25 0 * * * ?")
    public void executeProduceExcelTask1h() {
        readCoinPeriodStrategyExcel("1000satsusdt","1h",ModelEnum.random_forest);
        readCoinPeriodStrategyExcel("1000satsusdt","1h",ModelEnum.random_forest_v1);
    }

    @Scheduled(cron = "28 0 8 * * ?")
    public void executeProduceExcelTask1d() {
        readCoinPeriodStrategyExcel("1000satsusdt","1d",ModelEnum.random_forest);
        readCoinPeriodStrategyExcel("1000satsusdt","1d",ModelEnum.random_forest_v1);
    }

    @Scheduled(cron = "28 0 8 ? * MON")
    public void executeProduceExcelTask1w() {
        readCoinPeriodStrategyExcel("1000satsusdt","1w",ModelEnum.random_forest);
        readCoinPeriodStrategyExcel("1000satsusdt","1w",ModelEnum.random_forest_v1);
    }
    public void readCoinPeriodStrategyExcel(String coin, String period, ModelEnum modelEnum) {
        List<PredictInfoDto> predictInfoDtos = predictManager.queryCoinPeriodStrategy(coin, period, modelEnum);
        if (CollectionUtils.isEmpty(predictInfoDtos)) {
            log.info("get  queryCoinPeriodStrategy size 0 ");
            return;
        }
        predictInfoDtos.sort(Comparator.comparing(PredictInfoDto::getPredictClosetime));
        for (PredictInfoDto predictInfoDto : predictInfoDtos) {
            predictInfoDto.setPridictFinalStatus(checkPredictionAccuracy(predictInfoDto,predictInfoDtos));;
        }
        //生成对应的统计数据
        CountPredictInfoDto countPredictInfoDto = new CountPredictInfoDto();
        countPredictInfoDto.setCurrencyName(coin);
        countPredictInfoDto.setPeriodDimension(period);
        countPredictInfoDto.setModelName(modelEnum.name());
        countPredictInfoDto.setTotalNum(Long.parseLong(String.valueOf(predictInfoDtos.size())));
        Long success = predictInfoDtos.stream().filter(k -> k.getPridictFinalStatus().equals("success")).count();
        countPredictInfoDto.setSuccessNum(success);
        Long fail = predictInfoDtos.stream().filter(k -> k.getPridictFinalStatus().equals("fail")).count();
        countPredictInfoDto.setFailNum(fail);
        BigDecimal divideRate = new BigDecimal(countPredictInfoDto.getSuccessNum()).divide(new BigDecimal(countPredictInfoDto.getTotalNum()),3, BigDecimal.ROUND_HALF_UP);
        countPredictInfoDto.setCalSuccessRate(divideRate);
        //生成excel数据

        String projectRoot = System.getProperty("user.dir");
        String fileName = modelEnum.name() +"_"+ coin.toLowerCase() + "_" + period + ".csv";
        String relativeDirectory = "csv/file/resultshow";

        // 获取项目根路径的上一层目录
        Path parentOfProjectRoot = Paths.get(projectRoot).getParent();
        if (parentOfProjectRoot == null) {
            System.err.println("Parent directory of project root could not be determined.");
            return;
        }

        // 构建目标目录路径
        Path directoryPath = parentOfProjectRoot.resolve(relativeDirectory);

        // 如果目录不存在，创建目录
        try {
            if (Files.notExists(directoryPath)) {
                Files.createDirectories(directoryPath);
                System.out.println("Directory created: " + directoryPath.toString());
            } else {
                System.out.println("Directory already exists: " + directoryPath.toString());
            }
        } catch (IOException e) {
            System.err.println("Failed to create directory: " + directoryPath.toString());
            e.printStackTrace();
            return;
        }

        // 构建文件路径
        Path filePath = directoryPath.resolve(fileName);
        File file = filePath.toFile();

        // 用 Map 来存储去重后的数据，key 为序号
        Map<Integer, List<Object>> dataMap = new LinkedHashMap<>();

        // 如果文件存在，删除文件
        if (file.exists()) {
            file.delete();
        }
        // 将新的数据合并到 dataMap 中（按序号去重）
        for (PredictInfoDto dto : predictInfoDtos) {
            List<Object> newRow = CollUtil.newArrayList(
                    dto.getPredictUniqueTag(),
                    dto.getPredictBatchNum(),
                    dto.getPredictResult(),
                    DateUtil.formatDateTime(dto.getPredictClosetime()),
                    dto.getPredictCloseprice(),
                    DateUtil.formatDateTime(dto.getPredictCreateat()),
                    dto.getCurrencyName(),
                    dto.getPeriodDimension(),
                    dto.getResultCode(),
                    dto.getCurrentClosePrice(),
                    dto.getModelName(),
                    dto.getPridictFinalStatus()
            );
            dataMap.put(dto.getId(),newRow);
        }

        // 将 dataMap 转为 List，按照序号进行排序
        List<List<Object>> finalRows = new ArrayList<>(dataMap.values());


        // 写入 CSV 文件
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
            // 写入表头
            writer.write("预测唯一标识,预测批次号,预测结果,预测收盘时间,预测收盘价格,预测创建时间,币种名称,周期维度,结果代码,当前收盘价,模型名称,当前行数据预测是否正确");
            writer.newLine();

            // 写入数据
            for (List<Object> row : finalRows) {
                writer.write(String.join(",", rowToStringArray(row)));
                writer.newLine();
            }



            writer.write("totalNum,currencyName,periodDimension,modelName,successNum,FailNum,calSuccessRate");
            writer.newLine();
            List<Object> newRowShow = CollUtil.newArrayList(
                    countPredictInfoDto.getTotalNum(),countPredictInfoDto.getCurrencyName(),countPredictInfoDto.getPeriodDimension(),
                    countPredictInfoDto.getModelName(),countPredictInfoDto.getSuccessNum(),countPredictInfoDto.getFailNum(),
                    countPredictInfoDto.getCalSuccessRate()
            );
            writer.write(String.join(",", rowToStringArray(newRowShow)));
            writer.newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("Saved CSV with {} rows at: {}", finalRows.size(), filePath);

    }

    // 将 List<Object> 转为字符串数组，用于 CSV 写入
    private String[] rowToStringArray(List<Object> row) {
        return row.stream()
                .map(obj -> obj == null ? " " : obj.toString()) // 处理 null 值，确保转换为空字符串
                .toArray(String[]::new);
    }
    public String checkPredictionAccuracy(PredictInfoDto currentData, List<PredictInfoDto> allData) {
        // 获取当前数据的收盘时间
        Date currentCloseTime = currentData.getPredictClosetime();

        // 使用 Stream 找到下一个最近的收盘时间的数据
        Optional<PredictInfoDto> nextData = allData.stream()
                .filter(data -> data.getPredictClosetime().after(currentCloseTime))  // 过滤出收盘时间在当前之后的数据
                .min(Comparator.comparing(PredictInfoDto::getPredictClosetime));     // 找到收盘时间最近的一条数据

        // 如果找不到下一条数据，则无法进行比较，返回 false
        if (!nextData.isPresent()) {
            log.info("not found next min PredictClosetime");
            return ""; // 无法找到下一条数据，无法比较
        }

        // 获取下一条数据的收盘价
        PredictInfoDto next = nextData.get();
        BigDecimal currentClosePrice = currentData.getCurrentClosePrice();
        BigDecimal nextClosePrice = next.getCurrentClosePrice();

        if(currentClosePrice==null || nextClosePrice==null){
            log.info(" predictClosetime data loss");
            return ""; // 无法找到下一条数据，无法比较
        }
        // 判断涨跌
        String isUpString = currentClosePrice.compareTo(nextClosePrice)<0 ?"Up": currentClosePrice.compareTo(nextClosePrice)==0 ? "equal":"Down";  // 如果下一条收盘价比当前高，说明市场上涨
        String currentPredicteSuceOrFail = isUpString.equals(currentData.getPredictResult()) ?"success":"fail";  // 假设你有预测趋势字段
        if(isUpString.equals("equal")){
            return "equal";
        }
        // 返回预测结果是否正确
        return currentPredicteSuceOrFail;
    }

}
